import org.junit.Test;
import static org.junit.Assert.*;
import java.util.Map;
import java.util.HashMap;

public class ComputerAITests {
	private Map<Move, Integer> movesNecessariosParaRecriarTabuleiro(int[][] board) {
		// Moves necessarios para criar este board
		// A chave do tipo Integer corresponde a cor da peca que esta
		// a fazer o move
		Map<Move, Integer> movesNecessarios = new HashMap<Move, Integer>();
		
		for (int y = 0; y != board.length; y++) {
			for (int x = 0; x != board.length; x++) {
				if (board[y][x] == Color.WHITE) {
					movesNecessarios.put(new Move(y, x), Color.WHITE);
				}
				else if (board[y][x] == Color.BLACK) {
					movesNecessarios.put(new Move(y, x), Color.BLACK);
				}
			}
		}

		return movesNecessarios;
	}

	private Board criarTabuleiroAPartirDeArray(int[][] board) {
		Board tabuleiro = new Board(board.length);

		for (Map.Entry<Move, Integer> jogada : movesNecessariosParaRecriarTabuleiro(board).entrySet()) {
			tabuleiro.placePiece(jogada.getValue(), jogada.getKey());
		}

		return tabuleiro;
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao1() {
		/* Tabuleiro de tamanho 3
		 * 200
		 * 200
		 * 000
		 */
		int[][] board = {{2, 0, 0},
						 {2, 0, 0},
						 {0, 0, 0}};

		Board tabuleiro = criarTabuleiroAPartirDeArray(board);

		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);

		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}


	@Test
	public void computadorGanhaEmUmaJogadaVersao2() {
		/* Tabuleiro de tamanho 3
		 * 020
		 * 020
		 * 000
		 */
		int[][] board = {{0, 2, 0},
						 {0, 2, 0},
						 {0, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao3() {
		/* Tabuleiro de tamanho 3
		 * 002
		 * 002
		 * 000
		 */
		int[][] board = {{0, 0, 2},
						 {0, 0, 2},
						 {0, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao4() {
		/* Tabuleiro de tamanho 3
		 * 002
		 * 020
		 * 000
		 */
		int[][] board = {{0, 0, 2},
						 {0, 2, 0},
						 {0, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);


		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao5() {
		/* Tabuleiro de tamanho 3
		 * 220
		 * 020
		 * 000
		 */
		int[][] board = {{2, 2, 0},
						 {0, 2, 0},
						 {0, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao6() {
		/* Tabuleiro de tamanho 3
		 * 000
		 * 020
		 * 200
		 */
		int[][] board = {{0, 0, 0},
						 {0, 2, 0},
						 {2, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao7() {
		/* Tabuleiro de tamanho 3
		 * 000
		 * 200
		 * 200
		 */
		int[][] board = {{0, 0, 0},
						 {2, 0, 0},
						 {2, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao8() {
		/* Tabuleiro de tamanho 4
		 * 0211
		 * 0210
		 * 0210
		 * 1000
		 */
		int[][] board = {{0, 2, 1, 1},
						 {0, 2, 1, 0},
						 {0, 2, 1, 0},
						 {1, 0, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao9() {
		/* Tabuleiro de tamanho 4
		 * 0200
		 * 0200
		 * 0200
		 * 1011
		 */
		int[][] board = {{0, 2, 0, 0},
						 {0, 2, 0, 0},
						 {0, 2, 0, 0},
						 {1, 0, 1, 1}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());
	}

	@Test
	public void computadorGanhaEmUmaJogadaVersao10() {
		/* Tabuleiro de tamanho 4
		 * 0200
		 * 0200
		 * 0200
		 * 1011
		 *
		 * O proximo a jogar (independentemente da cor) ganha o jogo
		 */
		int[][] board = {{0, 2, 0, 0},
						 {0, 2, 0, 0},
						 {0, 2, 0, 0},
						 {1, 0, 1, 1}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveVencedor);
		
		assertTrue(tabuleiro.hasBlackWon());

		Board tabuleiro2 = criarTabuleiroAPartirDeArray(board);
		
		// Esta jogada devera terminar o jogo com uma victoria para as
		// pecas pretas
		Move moveVencedor2 = ComputerAI.makeMove(tabuleiro2, Color.WHITE, Player.CPU_EASY);
		
		tabuleiro2.placePiece(Color.WHITE, moveVencedor);
		
		assertTrue(tabuleiro2.hasWhiteWon());
	}

	@Test
	public void computadorFazJogadaNoCentroDoTabuleiro() {
		// Durante a primeira jogada, o computador devera tentar
		// colocar a sua peca no centro do tabuleiro (so se o tamanho
		// deste for par)

		Board tabuleiro = new Board(3);

		Move moveCentroBlack = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);

		assertEquals(1, moveCentroBlack.getLine());
		assertEquals(1, moveCentroBlack.getColumn());

		Move moveCentroWhite = ComputerAI.makeMove(tabuleiro, Color.WHITE, Player.CPU_EASY);

		assertEquals(1, moveCentroWhite.getLine());
		assertEquals(1, moveCentroWhite.getColumn());
	}

	@Test
	public void computadorImpedeVictoria1() {
		/* Tabuleiro de tamanho 4
		 * 0002
		 * 1110
		 * 0000
		 * 0000
		 */
		// O jogador branco ira ganhar da proxima vez que jogar

		int[][] board = {{0, 0, 0, 2},
						 {1, 1, 1, 0},
						 {0, 0, 0, 0},
						 {0, 0, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);

		// Esta jogada devera tapar o caminho das pecas brancas
		Move moveTapar = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveTapar);
		
		// Esta jogada nao devera conseguir ganhar o jogo
		Move moveJogadorBranco = ComputerAI.makeMove(tabuleiro, Color.WHITE, Player.CPU_EASY);

		tabuleiro.placePiece(Color.WHITE, moveJogadorBranco);

		assertFalse(tabuleiro.hasWhiteWon());
	}

	@Test
	public void computadorImpedeVictoria2() {
		/* Tabuleiro de tamanho 4
		 * 0000
		 * 1100
		 * 0000
		 * 0000
		 */
		// O jogador branco ira ganhar da proxima vez que jogar

		int[][] board = {{0, 0, 0, 0},
						 {1, 1, 0, 0},
						 {0, 0, 0, 0},
						 {0, 0, 0, 0}};
		
		Board tabuleiro = criarTabuleiroAPartirDeArray(board);

		// Esta jogada devera tapar o caminho das pecas brancas
		Move moveTapar = ComputerAI.makeMove(tabuleiro, Color.BLACK, Player.CPU_EASY);
		
		tabuleiro.placePiece(Color.BLACK, moveTapar);
		
		// Esta jogada nao devera conseguir ganhar o jogo
		Move moveJogadorBranco = ComputerAI.makeMove(tabuleiro, Color.WHITE, Player.CPU_EASY);

		tabuleiro.placePiece(Color.WHITE, moveJogadorBranco);

		// System.out.println(tabuleiro);
	}
}
